package com.example.flutter_jl_bluetooth_plugin

import android.bluetooth.BluetoothDevice
import android.content.Context
import android.text.TextUtils
import android.util.Log
import androidx.annotation.NonNull
import com.example.flutter_jl_bluetooth_plugin.ble.BleManager
import com.example.flutter_jl_bluetooth_plugin.ble.interfaces.BleEventCallback
import com.example.flutter_jl_bluetooth_plugin.ble.model.BleScanInfo
import com.example.flutter_jl_bluetooth_plugin.ota.OTAManager
import com.jieli.jl_bt_ota.constant.ErrorCode
import com.jieli.jl_bt_ota.constant.StateCode
import com.jieli.jl_bt_ota.interfaces.BtEventCallback
import com.jieli.jl_bt_ota.interfaces.IUpgradeCallback
import com.jieli.jl_bt_ota.model.BluetoothOTAConfigure
import com.jieli.jl_bt_ota.model.base.BaseError
import com.jieli.jl_bt_ota.util.BluetoothUtil
import com.jieli.jl_bt_ota.util.FileUtil
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.EventChannel.EventSink
import io.flutter.plugin.common.EventChannel.StreamHandler
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import java.io.File

/** FlutterJlBluetoothPlugin */
class FlutterJlBluetoothPlugin : FlutterPlugin, MethodCallHandler, StreamHandler {
    /// The MethodChannel that will the communication between Flutter and native Android
    ///
    /// This local reference serves to register the plugin with the Flutter Engine and unregister it
    /// when the Flutter Engine is detached from the Activity
    private lateinit var channel: MethodChannel
    private lateinit var eventChannel: EventChannel
    private var _eventSink: EventSink? = null

    private var mainApplicationContext: Context? = null

    private lateinit var mBleManager: BleManager
    private lateinit var mOTAManager: OTAManager

    companion object {
        var OTA_DIR = "upgrade"
    }

    override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        mainApplicationContext = flutterPluginBinding.applicationContext
        BleManager.initManager(mainApplicationContext)

        channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_jl_bluetooth_plugin")
        channel.setMethodCallHandler(this)
        eventChannel = EventChannel(
            flutterPluginBinding.binaryMessenger,
            "flutter_jl_bluetooth_plugin_event"
        )
        eventChannel.setStreamHandler(this)

        mBleManager = BleManager.getInstance()
        mBleManager.registerBleEventCallback(mBleCallback)
        val otaConfigure = BluetoothOTAConfigure.createDefault()
        otaConfigure.firmwareFilePath = FileUtil.splicingFilePath(mainApplicationContext, mainApplicationContext?.packageName, OTA_DIR, null, null) + "/update.ufw"
        mOTAManager = OTAManager(mainApplicationContext!!, otaConfigure)
        mOTAManager.registerBluetoothCallback(mBtCallback)
    }

    override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
        when (call.method) {
            "test" -> {
                _eventSink?.success("啊哈哈哈哈哈哈哈")
                result.success("This is Android!")
            }
            "JLPhoneBluetoothIsNotEnabled" -> {
                // 查询手机是否开启蓝牙
                result.success(mBleManager.isBluetoothEnable)
            }
            "JLBleGetDeviceConnected" -> {
                // 获取蓝牙设备是否连接
                result.success(mBleManager.isDevConnected)
            }
            "JLBleStartScanDevice" -> {
                // 搜索蓝牙设备
                result.success(mBleManager.startLeScan(12000))
            }
            "JLBleSetFilter" -> {
                // 设置蓝牙过滤，安卓OTA没覆盖到蓝牙过滤功能
                result.success(false)
            }
            "JLBleGetFilter" -> {
                // 获取蓝牙过滤，安卓OTA没覆盖到蓝牙过滤功能
                result.success(false)
            }
            "JLBleDeviceRequireConnect" -> {
                // 连接蓝牙设备
                val map = call.arguments as Map<String, Any>
                val address = map.getValue("address") as String
                val isUseDevAuth = map.getValue("ble_pair_enable") as Boolean
                mOTAManager.bluetoothOption.isUseAuthDevice = isUseDevAuth
                mBleManager.connectBleDevice(BluetoothUtil.getRemoteDevice(address))
                result.success(true)
            }
            "JLBleDeviceRequireDisconnect" -> {
                // 断开蓝牙设备
                mBleManager.disconnectBleDevice(mBleManager.connectedBtDevice)
                result.success(true)
            }
            "JLOTAGetFileList" -> {
                // 获取OTA升级文件数组
                val map = call.arguments as Map<String, Any>
                var dirPath = map.getValue("OTAFileDocPath") as String
                if (dirPath != null && !dirPath.isEmpty()) {
                    OTA_DIR = dirPath
                }
                dirPath = FileUtil.splicingFilePath(mainApplicationContext, mainApplicationContext?.packageName, OTA_DIR, null, null)
                val parent = File(dirPath)
                var files: Array<File> = arrayOf()  //文件列表
                if (parent.exists()) {
                    parent.listFiles()?.iterator()?.forEach {
                        if (it.name.endsWith(".ufw") || it.name.endsWith(".bfu")) {
                            files = files.plus(it)
                        }
                    }
                } else {
                    parent.mkdirs()
                }
                val filePathList = arrayListOf<String>()
                files.forEach {
                    val strList = it.path.split('/')
                    filePathList.add(strList.last())
                }
                result.success(filePathList)
            }
            "JLOTASetSelectFilePath" -> {
                // 设置OTA升级文件路径
                val map = call.arguments as Map<String, Any>
                val filePath = map.getValue("selectOTAFilePath") as String
                mOTAManager.bluetoothOption.firmwareFilePath = FileUtil.splicingFilePath(mainApplicationContext, mainApplicationContext?.packageName, OTA_DIR, null, null) + "/" + filePath
                result.success(true)
            }
            "JLOTAGetSelectFilePath" -> {
                // 获取OTA升级文件路径
                result.success(mOTAManager.bluetoothOption.firmwareFilePath)
            }
            "JLOtaGetBleDeviceInfoAndStartOtaUpgrade" -> {
                // 获取设备信息，并进行OTA升级
                mOTAManager.startOTA(mOTACallback)
                result.success(true)
            }
            else -> {
                result.notImplemented()
            }
        }
    }

    override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
        channel.setMethodCallHandler(null)
        mBleManager.unregisterBleEventCallback(mBleCallback)
        mOTAManager.unregisterBluetoothCallback(mBtCallback)
        mOTAManager.release()
        mBleManager.destroy()
        _eventSink = null
    }

    override fun onListen(o: Any?, eventSink: EventSink) {
        Log.e("BluetoothPlugin", "onListen")
        _eventSink = eventSink
    }

    override fun onCancel(o: Any?) {
//        _eventSink = null
    }

    private fun putDeviceToList(list: List<Map<Any, Any>>, index: Int, device: BluetoothDevice): List<Map<Any, Any>> {
        for (mPeripheralMap in list) {
            if (mPeripheralMap["address"] == device.address) { //设备已存在，不添加到列表中
                return list
            }
        }
        if (!TextUtils.isEmpty(device.name)) {
            // 扫描到数据添加到数组
            val mPeripheralMap = HashMap<Any, Any>()
            val isConnected = mBleManager.isConnectedDevice(device)
            mPeripheralMap["name"] = device.name
            mPeripheralMap["address"] = device.address
            if (isConnected) {
                mPeripheralMap["state"] = 2
            } else {
                mPeripheralMap["state"] = 0
            }
            return list.plus(mPeripheralMap)
        }
        return list
    }

    private fun postDiscoveryBleList(list: List<BluetoothDevice>?) {
        var result: List<Map<Any, Any>> = arrayListOf()
        if (mBleManager.connectedBtDevice != null) {
            result = putDeviceToList(result, 0, mBleManager.connectedBtDevice)
        }
        if (list != null && list.isNotEmpty()) {
            for ((i, it) in list.withIndex()) {
                result = putDeviceToList(result, i, it)
            }
        }
        val discoveryList = HashMap<String, Any>()
        discoveryList["EventName"] = "JLBleUpdateDeviceListView"
        discoveryList["EventObject"] = result
        _eventSink?.success(discoveryList)
    }

    private fun postBtConnectionStatus(state: String) {
        val map = HashMap<String, Any>()
        map["EventName"] = state
        map["EventObject"] = true
        _eventSink?.success(map)

        postDiscoveryBleList(mBleManager.discoveredBleDevices)
    }

    private fun postOTAStatus(state: String) {
        val map = HashMap<String, Any>()
        map["EventName"] = state
        _eventSink?.success(map)
    }

    private val mBleCallback = object : BleEventCallback() {
        override fun onAdapterChange(bEnabled: Boolean) {
            if (!bEnabled) {
                postDiscoveryBleList(null)
            }
        }

        override fun onDiscoveryBleChange(bStart: Boolean) {
            if (bStart) {
                postDiscoveryBleList(null)
            }
        }

        override fun onDiscoveryBle(device: BluetoothDevice?, bleScanMessage: BleScanInfo?) {
            postDiscoveryBleList(mBleManager.discoveredBleDevices)
        }
    }

    private val mBtCallback = object : BtEventCallback() {
        override fun onConnection(device: BluetoothDevice?, status: Int) {
            when (status) {
                StateCode.CONNECTION_OK, StateCode.CONNECTION_CONNECTED -> { //连接成功
                    postBtConnectionStatus("JLBleDeviceConnected")
                }
                StateCode.CONNECTION_CONNECTING -> {//连接中

                }
                else -> { //断开连接
                    postBtConnectionStatus("JLBleDeviceDisconnected")
                }
            }
        }
    }

    private val mOTACallback = object : IUpgradeCallback {
        override fun onCancelOTA() { //取消OTA

        }

        override fun onNeedReconnect(p0: String?) { //需要进行回连，如果不是自定义回连可以忽略
            //TODO://可能要增加地址参数
            postOTAStatus("JLOtaBleDeviceReconnect")
        }

        override fun onStopOTA() { //OTA完成
            postOTAStatus("JLOtaUpgradeSuccess")
        }

        override fun onProgress(p0: Int, p1: Float) { //OTA进度，0 -- bootloader , 1  -- sdk
            val map = HashMap<String, Any>()
            val state = if (p0 == 1) {
                "JLOtaUpgrading"
            } else {
                "JLOtaUpgradePreparing"
            }
            val paramMap = HashMap<String, Any>()
            paramMap["progress"] = p1.toDouble() / 100
            map["EventName"] = state
            map["EventObject"] = paramMap
            _eventSink?.success(map)
        }

        override fun onStartOTA() { //开始OTA
            postOTAStatus("JLOtaUpgradePrepared")
        }

        override fun onError(p0: BaseError?) { //OTA发生错误
            when (p0?.subCode) {
                ErrorCode.SUB_ERR_OTA_IN_HANDLE -> { //正在OTA中，不需要重复操作

                }
                ErrorCode.SUB_ERR_UPGRADE_KEY_NOT_MATCH -> { //升级文件key不匹配
                    postOTAStatus("JLOtaUpgradeFileKeyError")
                }
                ErrorCode.SUB_ERR_OTA_FAILED -> { //OTA失败
                    postOTAStatus("JLOtaUpgradeFailed")
                }
                ErrorCode.SUB_ERR_CHECK_UPGRADE_FILE -> {//升级文件错误
                    postOTAStatus("JLOtaUpgradeFileError")
                }
                ErrorCode.SUB_ERR_UPGRADE_FILE_VERSION_SAME -> { //版本一致

                }
                ErrorCode.SUB_ERR_UPGRADE_CMD_TIMEOUT -> { //命令超时
                    postOTAStatus("JLOtaUpgradeCloseOverTimeCheck")
                }
                ErrorCode.SUB_ERR_UPGRADE_FLASH_READ -> { //Flash读写异常

                }
                ErrorCode.SUB_ERR_UPGRADE_DATA_LEN -> { //升级文件数据长度异常

                }
                ErrorCode.SUB_ERR_TWS_NOT_CONNECT -> { //耳机没处于配对状态

                }
                ErrorCode.SUB_ERR_UPGRADE_TYPE_NOT_MATCH -> { //升级类型不匹配

                }
            }
        }
    }
}
